package pers.xiqingbo.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @PackageName: pers.xiqingbo.utils
 * @ClassName: JdbcUtils
 * @Description: 获取数据库连接
 * @Author: Schieber
 * @Date: 2021/1/31 上午 10:00
 */
public class JdbcUtils {
    /**
     * 创建druid数据源操作对象
     */
    private static DruidDataSource druidDataSource;

    /**
     * 使用ThreadLocal将数据库连接对象保存在线程变量中
     */
    private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();

    /**
     * 获取druid数据源操作对象
     */
    static {
        try {
            // 创建属性操作对象
            Properties properties = new Properties();
            // 使用类加载器通过流的形式获取到指定资源
            InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            // 属性对象通过读取流的方式加载资源文件
            properties.load(inputStream);
            // druid数据源工厂通过读取到的数据库连接配置信息赋值给数据源操作对象
            druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     *
     * @return 数据库连接对象
     */
    public static Connection getConnection() {
        // 创建连接对象
        Connection connection = null;
        // 将线程中保存的连接对象赋值给当前连接
        connection = connectionThreadLocal.get();
        if (connection == null) {
            try {
                // druid数据源操作对象获取连接
                connection = druidDataSource.getConnection();
                // 将连接对象保存在ThreadLocal中，供后面的JDBC操作使用
                connectionThreadLocal.set(connection);
                // 设置手动提交事务
                connection.setAutoCommit(false);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        return connection;
    }

    /**
     * 提交事务并关闭数据库连接
     */
    public static void commitAndClose() {
        // 从线程中获取连接对象
        Connection connection = connectionThreadLocal.get();
        // 如果连接不为空，说明当前线程建立过连接，操作过数据库
        if (connection != null) {
            try {
                // 提交事务
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                // 使用druid提供封装的方法悄悄关闭连接
                DbUtils.closeQuietly(connection);
            }
        }
        // 一定要执行remove()操作，否则会发生错误（因为Tomcat服务器底层使用了线程池技术）
        connectionThreadLocal.remove();
    }

    /**
     * 回滚事务并关闭数据库连接
     */
    public static void rollbackAndClose() {
        // 从线程中获取连接对象
        Connection connection = connectionThreadLocal.get();
        // 如果连接不为空，说明当前线程建立过连接，操作过数据库
        if (connection != null) {
            try {
                // 回滚事务
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                // 使用druid提供封装的方法悄悄关闭连接
                DbUtils.closeQuietly(connection);
            }
        }
        // 一定要执行remove()操作，否则会发生错误（因为Tomcat服务器底层使用了线程池技术）
        connectionThreadLocal.remove();
    }
}
